From 0bfc95f5b02bf7cf90fa1a0a8a9fbd48ee1a1d47 Mon Sep 17 00:00:00 2001 From: "kaf24@freefall.cl.cam.ac.uk" Date: Sat, 18 Sep 2004 10:43:00 +0000 Subject: [PATCH] bitkeeper revision 1.1159.79.2 (414c1134FG1zvS9xwv2yPDvyS7W3ig) Linux scrubs memory before returnign it to Xen, or transferring it to other domains (e.g., net backend driver). To avoid continual scrubbing during network transfers, I allocate rx skbuffs from a dedicated slab cache. Pages only neded to be scrubbed on entry to the cache, which should be ratehr more occasional than allocs/frees. Finally, scrubbing can be entirely disabled via a config option under the 'XEN' menu in the 2.4 and 2.6 kernel configurators. --- .rootkeys | 1 + linux-2.4.27-xen-sparse/arch/xen/config.in | 1 + .../arch/xen/defconfig-xen0 | 1 + .../arch/xen/defconfig-xenU | 1 + .../arch/xen/drivers/balloon/balloon.c | 18 ++++- .../arch/xen/kernel/Makefile | 4 +- .../include/asm-xen/page.h | 7 ++ .../include/linux/skbuff.h | 11 ++- linux-2.4.27-xen-sparse/mkbuildtree | 1 + linux-2.6.8.1-xen-sparse/arch/xen/Kconfig | 16 ++++- .../arch/xen/configs/xen0_defconfig | 3 +- .../arch/xen/configs/xenU_defconfig | 3 +- .../arch/xen/i386/kernel/pci-dma.c | 1 + .../arch/xen/i386/mm/hypervisor.c | 2 + .../arch/xen/kernel/Makefile | 2 +- .../arch/xen/kernel/skbuff.c | 68 +++++++++++++++++++ .../drivers/xen/netback/netback.c | 2 +- .../drivers/xen/netfront/netfront.c | 34 ++++------ .../include/asm-xen/asm-i386/page.h | 7 ++ .../include/linux/skbuff.h | 10 +-- xen/common/page_alloc.c | 20 ++++-- 21 files changed, 163 insertions(+), 50 deletions(-) create mode 100644 linux-2.6.8.1-xen-sparse/arch/xen/kernel/skbuff.c diff --git a/.rootkeys b/.rootkeys index 045d64edb3..640b527505 100644 --- a/.rootkeys +++ b/.rootkeys @@ -176,6 +176,7 @@ 412dfae9eA3_6e6bCGUtg1mj8b56fQ linux-2.6.8.1-xen-sparse/arch/xen/kernel/gnttab.c 40f56239sFcjHiIRmnObRIDF-zaeKQ linux-2.6.8.1-xen-sparse/arch/xen/kernel/process.c 40f562392LBhwmOxVPsYdkYXMxI_ZQ linux-2.6.8.1-xen-sparse/arch/xen/kernel/reboot.c +414c113396tK1HTVeUalm3u-1DF16g linux-2.6.8.1-xen-sparse/arch/xen/kernel/skbuff.c 3f68905c5eiA-lBMQSvXLMWS1ikDEA linux-2.6.8.1-xen-sparse/arch/xen/kernel/xen_proc.c 41261688yS8eAyy-7kzG4KBs0xbYCA linux-2.6.8.1-xen-sparse/drivers/Makefile 4108f5c1WfTIrs0HZFeV39sttekCTw linux-2.6.8.1-xen-sparse/drivers/char/mem.c diff --git a/linux-2.4.27-xen-sparse/arch/xen/config.in b/linux-2.4.27-xen-sparse/arch/xen/config.in index 8fa004a16b..d6a3936547 100644 --- a/linux-2.4.27-xen-sparse/arch/xen/config.in +++ b/linux-2.4.27-xen-sparse/arch/xen/config.in @@ -16,6 +16,7 @@ mainmenu_option next_comment comment 'Xen' bool 'Support for privileged operations (domain 0)' CONFIG_XEN_PRIVILEGED_GUEST bool 'Device-driver domain (physical device access)' CONFIG_XEN_PHYSDEV_ACCESS +bool 'Scrub memory before freeing it to Xen' CONFIG_XEN_SCRUB_PAGES endmenu # The IBM S/390 patch needs this. define_bool CONFIG_NO_IDLE_HZ y diff --git a/linux-2.4.27-xen-sparse/arch/xen/defconfig-xen0 b/linux-2.4.27-xen-sparse/arch/xen/defconfig-xen0 index 1f0dcfc70d..21b0a99eab 100644 --- a/linux-2.4.27-xen-sparse/arch/xen/defconfig-xen0 +++ b/linux-2.4.27-xen-sparse/arch/xen/defconfig-xen0 @@ -12,6 +12,7 @@ CONFIG_UID16=y # CONFIG_XEN_PRIVILEGED_GUEST=y CONFIG_XEN_PHYSDEV_ACCESS=y +CONFIG_XEN_SCRUB_PAGES=y CONFIG_NO_IDLE_HZ=y CONFIG_FOREIGN_PAGES=y diff --git a/linux-2.4.27-xen-sparse/arch/xen/defconfig-xenU b/linux-2.4.27-xen-sparse/arch/xen/defconfig-xenU index e31d05679e..a975cc9f9f 100644 --- a/linux-2.4.27-xen-sparse/arch/xen/defconfig-xenU +++ b/linux-2.4.27-xen-sparse/arch/xen/defconfig-xenU @@ -12,6 +12,7 @@ CONFIG_UID16=y # # CONFIG_XEN_PRIVILEGED_GUEST is not set # CONFIG_XEN_PHYSDEV_ACCESS is not set +CONFIG_XEN_SCRUB_PAGES=y CONFIG_NO_IDLE_HZ=y # CONFIG_FOREIGN_PAGES is not set CONFIG_NETDEVICES=y diff --git a/linux-2.4.27-xen-sparse/arch/xen/drivers/balloon/balloon.c b/linux-2.4.27-xen-sparse/arch/xen/drivers/balloon/balloon.c index b13e3d75ef..c1a22a21f2 100644 --- a/linux-2.4.27-xen-sparse/arch/xen/drivers/balloon/balloon.c +++ b/linux-2.4.27-xen-sparse/arch/xen/drivers/balloon/balloon.c @@ -104,8 +104,20 @@ static unsigned long inflate_balloon(unsigned long num_pages) { unsigned long mfn = phys_to_machine_mapping[*currp]; curraddr = (unsigned long)page_address(mem_map + *currp); + /* Blow away page contents for security, and also p.t. ref if any. */ if ( curraddr != 0 ) + { + scrub_pages(curraddr, 1); queue_l1_entry_update(get_ptep(curraddr), 0); + } +#ifdef CONFIG_XEN_SCRUB_PAGES + else + { + void *p = kmap(&mem_map[*currp]); + scrub_pages(p, 1); + kunmap(&mem_map[*currp]); + } +#endif phys_to_machine_mapping[*currp] = DEAD; *currp = mfn; } @@ -388,9 +400,9 @@ static int balloon_write(struct file *file, const char *buffer, } len = strnlen_user(buffer, count); - if (len==0) return -EBADMSG; - if (len==1) return 1; /* input starts with a NUL char */ - if ( strncpy_from_user(memstring, buffer, len) < 0) + if ( len == 0 ) return -EBADMSG; + if ( len == 1 ) return 1; /* input starts with a NUL char */ + if ( strncpy_from_user(memstring, buffer, len) < 0 ) return -EFAULT; endchar = memstring; diff --git a/linux-2.4.27-xen-sparse/arch/xen/kernel/Makefile b/linux-2.4.27-xen-sparse/arch/xen/kernel/Makefile index 3ad868e357..30488e666b 100644 --- a/linux-2.4.27-xen-sparse/arch/xen/kernel/Makefile +++ b/linux-2.4.27-xen-sparse/arch/xen/kernel/Makefile @@ -6,12 +6,12 @@ all: kernel.o head.o init_task.o O_TARGET := kernel.o -export-objs := i386_ksyms.o gnttab.o +export-objs := i386_ksyms.o gnttab.o skbuff.o obj-y := process.o semaphore.o signal.o entry.o traps.o irq.o \ ptrace.o ioport.o ldt.o setup.o time.o sys_i386.o \ i386_ksyms.o i387.o evtchn.o ctrl_if.o pci-dma.o \ - reboot.o fixup.o gnttab.o + reboot.o fixup.o gnttab.o skbuff.o ifdef CONFIG_PCI obj-y += pci-i386.o pci-pc.o diff --git a/linux-2.4.27-xen-sparse/include/asm-xen/page.h b/linux-2.4.27-xen-sparse/include/asm-xen/page.h index 6826f65cc0..26e504485b 100644 --- a/linux-2.4.27-xen-sparse/include/asm-xen/page.h +++ b/linux-2.4.27-xen-sparse/include/asm-xen/page.h @@ -10,9 +10,16 @@ #ifndef __ASSEMBLY__ #include +#include #include #include +#ifdef CONFIG_XEN_SCRUB_PAGES +#define scrub_pages(_p,_n) memset((void *)(_p), 0, (_n) << PAGE_SHIFT) +#else +#define scrub_pages(_p,_n) ((void)0) +#endif + #ifdef CONFIG_X86_USE_3DNOW #include diff --git a/linux-2.4.27-xen-sparse/include/linux/skbuff.h b/linux-2.4.27-xen-sparse/include/linux/skbuff.h index 9698aa216c..009c29bcf6 100644 --- a/linux-2.4.27-xen-sparse/include/linux/skbuff.h +++ b/linux-2.4.27-xen-sparse/include/linux/skbuff.h @@ -1027,19 +1027,18 @@ static inline void __skb_queue_purge(struct sk_buff_head *list) * * %NULL is returned in there is no free memory. */ - +#ifndef CONFIG_XEN static inline struct sk_buff *__dev_alloc_skb(unsigned int length, int gfp_mask) { - struct sk_buff *skb; -#if defined(CONFIG_XEN) - length = (PAGE_SIZE/2)+1; /* force slab allocater to give us a page */ -#endif - skb = alloc_skb(length+16, gfp_mask); + struct sk_buff *skb = alloc_skb(length+16, gfp_mask); if (skb) skb_reserve(skb,16); return skb; } +#else +extern struct sk_buff *__dev_alloc_skb(unsigned int length, int gfp_mask); +#endif /** * dev_alloc_skb - allocate an skbuff for sending diff --git a/linux-2.4.27-xen-sparse/mkbuildtree b/linux-2.4.27-xen-sparse/mkbuildtree index decd9037d5..300b15cb73 100755 --- a/linux-2.4.27-xen-sparse/mkbuildtree +++ b/linux-2.4.27-xen-sparse/mkbuildtree @@ -228,6 +228,7 @@ ln -sf ../../../${LINUX_26}/arch/xen/kernel/evtchn.c ln -sf ../../../${LINUX_26}/arch/xen/kernel/fixup.c ln -sf ../../../${LINUX_26}/arch/xen/kernel/gnttab.c ln -sf ../../../${LINUX_26}/arch/xen/kernel/reboot.c +ln -sf ../../../${LINUX_26}/arch/xen/kernel/skbuff.c ln -sf ../../../${LINUX_26}/arch/xen/i386/kernel/ioport.c ln -sf ../../../${LINUX_26}/arch/xen/i386/kernel/pci-dma.c diff --git a/linux-2.6.8.1-xen-sparse/arch/xen/Kconfig b/linux-2.6.8.1-xen-sparse/arch/xen/Kconfig index a7e3994e10..57e3ebaf95 100644 --- a/linux-2.6.8.1-xen-sparse/arch/xen/Kconfig +++ b/linux-2.6.8.1-xen-sparse/arch/xen/Kconfig @@ -100,16 +100,26 @@ config XEN_WRITABLE_PAGETABLES help Use writable L1 pagetables +config XEN_SCRUB_PAGES + bool "Scrub memory before freeing it to Xen" + default y + help + Erase memory contents before freeing it back to Xen's global + pool. This ensures that any secrets contained within that + memory (e.g., private keys) cannot be found by other guests that + may be running on the machine. Most people will want to say Y here. + If security is not a concern then you may increase performance by + saying N. + endmenu config FOREIGN_PAGES bool default y -config PAGESIZED_SKBS +config HAVE_ARCH_DEV_ALLOC_SKB bool - default y if XEN_NETDEV_BACKEND - default n if !XEN_NETDEV_BACKEND + default y #config VT # bool diff --git a/linux-2.6.8.1-xen-sparse/arch/xen/configs/xen0_defconfig b/linux-2.6.8.1-xen-sparse/arch/xen/configs/xen0_defconfig index a118d649cc..42aeb485be 100644 --- a/linux-2.6.8.1-xen-sparse/arch/xen/configs/xen0_defconfig +++ b/linux-2.6.8.1-xen-sparse/arch/xen/configs/xen0_defconfig @@ -16,8 +16,9 @@ CONFIG_XEN_BLKDEV_FRONTEND=y CONFIG_XEN_NETDEV_FRONTEND=y # CONFIG_XEN_NETDEV_FRONTEND_PIPELINED_TRANSMITTER is not set CONFIG_XEN_WRITABLE_PAGETABLES=y +CONFIG_XEN_SCRUB_PAGES=y CONFIG_FOREIGN_PAGES=y -CONFIG_PAGESIZED_SKBS=y +CONFIG_HAVE_ARCH_DEV_ALLOC_SKB=y CONFIG_X86=y # CONFIG_X86_64 is not set diff --git a/linux-2.6.8.1-xen-sparse/arch/xen/configs/xenU_defconfig b/linux-2.6.8.1-xen-sparse/arch/xen/configs/xenU_defconfig index a3efc64d58..d6940f6fec 100644 --- a/linux-2.6.8.1-xen-sparse/arch/xen/configs/xenU_defconfig +++ b/linux-2.6.8.1-xen-sparse/arch/xen/configs/xenU_defconfig @@ -16,8 +16,9 @@ CONFIG_XEN_BLKDEV_FRONTEND=y CONFIG_XEN_NETDEV_FRONTEND=y # CONFIG_XEN_NETDEV_FRONTEND_PIPELINED_TRANSMITTER is not set CONFIG_XEN_WRITABLE_PAGETABLES=y +CONFIG_XEN_SCRUB_PAGES=y CONFIG_FOREIGN_PAGES=y -# CONFIG_PAGESIZED_SKBS is not set +CONFIG_HAVE_ARCH_DEV_ALLOC_SKB=y CONFIG_X86=y # CONFIG_X86_64 is not set diff --git a/linux-2.6.8.1-xen-sparse/arch/xen/i386/kernel/pci-dma.c b/linux-2.6.8.1-xen-sparse/arch/xen/i386/kernel/pci-dma.c index 6135d057b2..cc9bd03e12 100644 --- a/linux-2.6.8.1-xen-sparse/arch/xen/i386/kernel/pci-dma.c +++ b/linux-2.6.8.1-xen-sparse/arch/xen/i386/kernel/pci-dma.c @@ -55,6 +55,7 @@ void *dma_alloc_coherent(struct device *dev, size_t size, pmd_t *pmd; pte_t *pte; unsigned long pfn, i; + scrub_pages(vstart, 1 << order); /* 1. Zap current PTEs, giving away the underlying pages. */ for (i = 0; i < (1< +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +EXPORT_SYMBOL(__dev_alloc_skb); + +static kmem_cache_t *skbuff_cachep; + +struct sk_buff *__dev_alloc_skb(unsigned int length, int gfp_mask) +{ + struct sk_buff *skb; + u8 *new_data, *new_shinfo; + + /* + * Yuk! There is no way to get a skbuff head without allocating the + * data area using kmalloc(). So we do that and then replace the default + * data area with our own. + */ + skb = alloc_skb(0, gfp_mask); + if ( unlikely(skb == NULL) ) + return NULL; + + new_data = kmem_cache_alloc(skbuff_cachep, gfp_mask); + if ( new_data == NULL ) + { + dev_kfree_skb(skb); + return NULL; + } + + new_shinfo = + new_data + PAGE_SIZE - sizeof(struct skb_shared_info); + memcpy(new_shinfo, skb_shinfo(skb), sizeof(struct skb_shared_info)); + + kfree(skb->head); + + skb->head = new_data; + skb->data = skb->tail = new_data + 16; /* __dev_alloc_skb does this */ + skb->end = new_shinfo; + skb->truesize = 1500; /* is this important? */ + + return skb; +} + +static void skbuff_ctor(void *buf, kmem_cache_t *cachep, unsigned long unused) +{ + scrub_pages(buf, 1); +} + +static int __init skbuff_init(void) +{ + skbuff_cachep = kmem_cache_create( + "xen-skb", PAGE_SIZE, PAGE_SIZE, 0, skbuff_ctor, NULL); + return 0; +} +__initcall(skbuff_init); diff --git a/linux-2.6.8.1-xen-sparse/drivers/xen/netback/netback.c b/linux-2.6.8.1-xen-sparse/drivers/xen/netback/netback.c index 296771b837..242f500780 100644 --- a/linux-2.6.8.1-xen-sparse/drivers/xen/netback/netback.c +++ b/linux-2.6.8.1-xen-sparse/drivers/xen/netback/netback.c @@ -132,7 +132,7 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev) (((unsigned long)skb->end ^ (unsigned long)skb->head) & PAGE_MASK) || ((skb->end - skb->head) < (PAGE_SIZE/2)) ) { - struct sk_buff *nskb = alloc_skb(PAGE_SIZE-1024, GFP_ATOMIC); + struct sk_buff *nskb = dev_alloc_skb(PAGE_SIZE); int hlen = skb->data - skb->head; if ( unlikely(nskb == NULL) ) goto drop; diff --git a/linux-2.6.8.1-xen-sparse/drivers/xen/netfront/netfront.c b/linux-2.6.8.1-xen-sparse/drivers/xen/netfront/netfront.c index 683dd616da..f04c6a1b59 100644 --- a/linux-2.6.8.1-xen-sparse/drivers/xen/netfront/netfront.c +++ b/linux-2.6.8.1-xen-sparse/drivers/xen/netfront/netfront.c @@ -39,6 +39,7 @@ #ifndef __GFP_NOWARN #define __GFP_NOWARN 0 #endif +#define alloc_skb_page() __dev_alloc_skb(PAGE_SIZE, GFP_ATOMIC|__GFP_NOWARN) /* * If the backend driver is pipelining transmit requests then we can be very @@ -193,35 +194,24 @@ static int netctrl_connected_count(void) * @param dev device * @return 0 on success, error code otherwise */ -static int vif_wake(struct net_device *dev){ - int err = 0; +static int vif_wake(struct net_device *dev) +{ struct sk_buff *skb; - u32 src_ip; - u32 dst_ip = INADDR_BROADCAST; - unsigned char dst_hw[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + u32 src_ip, dst_ip; + unsigned char dst_hw[ETH_ALEN]; + memset(dst_hw, 0xff, ETH_ALEN); + + dst_ip = INADDR_BROADCAST; src_ip = inet_select_addr(dev, dst_ip, RT_SCOPE_LINK); + skb = arp_create(ARPOP_REQUEST, ETH_P_ARP, dst_ip, dev, src_ip, dst_hw, dev->dev_addr, NULL); - if(skb == NULL){ - err = -ENOMEM; - goto exit; - } - err = dev_queue_xmit(skb); - exit: - return err; -} + if ( skb == NULL ) + return -ENOMEM; -static inline struct sk_buff *alloc_skb_page(void) -{ - struct sk_buff *skb; - skb = __dev_alloc_skb((PAGE_SIZE/2)+1, GFP_ATOMIC|__GFP_NOWARN); -#if 0 - if ( skb && unlikely(((unsigned long)skb->head & (PAGE_SIZE-1)) != 0) ) - panic("alloc_skb needs to provide us page-aligned buffers."); -#endif - return skb; + return dev_queue_xmit(skb); } static int network_open(struct net_device *dev) diff --git a/linux-2.6.8.1-xen-sparse/include/asm-xen/asm-i386/page.h b/linux-2.6.8.1-xen-sparse/include/asm-xen/asm-i386/page.h index 129c68f419..ce9a1c6cf3 100644 --- a/linux-2.6.8.1-xen-sparse/include/asm-xen/asm-i386/page.h +++ b/linux-2.6.8.1-xen-sparse/include/asm-xen/asm-i386/page.h @@ -13,9 +13,16 @@ #ifndef __ASSEMBLY__ #include +#include #include #include +#ifdef CONFIG_XEN_SCRUB_PAGES +#define scrub_pages(_p,_n) memset((void *)(_p), 0, (_n) << PAGE_SHIFT) +#else +#define scrub_pages(_p,_n) ((void)0) +#endif + #ifdef CONFIG_X86_USE_3DNOW #include diff --git a/linux-2.6.8.1-xen-sparse/include/linux/skbuff.h b/linux-2.6.8.1-xen-sparse/include/linux/skbuff.h index ba4e27dbc5..5f77865c22 100644 --- a/linux-2.6.8.1-xen-sparse/include/linux/skbuff.h +++ b/linux-2.6.8.1-xen-sparse/include/linux/skbuff.h @@ -936,18 +936,18 @@ static inline void __skb_queue_purge(struct sk_buff_head *list) * * %NULL is returned in there is no free memory. */ +#ifndef CONFIG_HAVE_ARCH_DEV_ALLOC_SKB static inline struct sk_buff *__dev_alloc_skb(unsigned int length, int gfp_mask) { - struct sk_buff *skb; -#ifdef CONFIG_PAGESIZED_SKBS - length = max(length, (unsigned int)(PAGE_SIZE - 16)); -#endif - skb = alloc_skb(length + 16, gfp_mask); + struct sk_buff *skb = alloc_skb(length + 16, gfp_mask); if (likely(skb)) skb_reserve(skb, 16); return skb; } +#else +extern struct sk_buff *__dev_alloc_skb(unsigned int length, int gfp_mask); +#endif /** * dev_alloc_skb - allocate an skbuff for sending diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c index 1d4d476464..7e793d4607 100644 --- a/xen/common/page_alloc.c +++ b/xen/common/page_alloc.c @@ -28,6 +28,7 @@ #include #include #include +#include extern char opt_badpage[]; @@ -427,6 +428,7 @@ void free_domheap_pages(struct pfn_info *pg, int order) { int i, drop_dom_ref; struct domain *d = pg->u.inuse.domain; + void *p; if ( unlikely(IS_XEN_HEAP_FRAME(pg)) ) { @@ -448,14 +450,22 @@ void free_domheap_pages(struct pfn_info *pg, int order) for ( i = 0; i < (1 << order); i++ ) { -#ifndef NDEBUG - if ( pg[i].u.inuse.type_info & PGT_count_mask ) - printk("ERROR: type count not zero on free %x\n", - pg[i].u.inuse.type_info ); -#endif + ASSERT((pg[i].u.inuse.type_info & PGT_count_mask) == 0); pg[i].tlbflush_timestamp = tlbflush_clock; pg[i].u.free.cpu_mask = 1 << d->processor; list_del(&pg[i].list); + + /* + * Normally we expect a domain to clear pages before freeing them, + * if it cares about the secrecy of their contents. However, after + * a domain has died we assume responsibility for erasure. + */ + if ( unlikely(test_bit(DF_DYING, &d->flags)) ) + { + p = map_domain_mem(page_to_phys(&pg[i])); + clear_page(p); + unmap_domain_mem(p); + } } d->tot_pages -= 1 << order; -- 2.30.2